#![no_std]
#![feature(negative_impls)]
#![allow(dead_code)]

extern crate alloc;

#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
#[allow(improper_ctypes)] //for 128-bit integers don't currently have a known stable ABI
mod ffi;
mod paho;

use crate::paho::PahoMqttClient;
use alloc::boxed::Box;
use embed_std::infoln;
use embed_std::Result;

pub struct MqttConnectOption<'a> {
    pub ver: u8,
    pub client_id: &'a str,
    pub user: &'a str,
    pub passwd: &'a str,
    pub keep_alive_interval: u32,
    pub command_timeout: u32,
    pub lwt: Option<LwtOption<'a>>,
}

#[derive(Debug)]
pub struct LwtOption<'a> {
    pub topic: &'a str,
    pub payload: &'a [u8],
    pub qos: u8,
    pub retain: bool,
}

const QOS0: u8 = 0;
const QOS1: u8 = 1;
const QOS2: u8 = 2;

pub struct MqttMessage<'a> {
    pub qos: u8,
    pub retained: u8,
    pub dup: u8,
    pub msg_id: u16,
    pub payload: &'a [u8],
}

pub trait MqttHandler {
    fn handle(&self, topic: &str, msg: &MqttMessage);
}

pub trait MqttClient: Send {
    fn init(&mut self, handler: Option<Box<dyn MqttHandler + Send>>) -> Result<()>;
    fn connect(&mut self, server: &str, port: u16, opts: &MqttConnectOption) -> Result<()>;
    fn disconnect(&mut self) -> Result<()>;
    fn subscribe(&mut self, topic: &str, qos: u8) -> Result<()>;
    fn unsubscribe(&mut self, topic: &str) -> Result<()>;
    fn publish(&mut self, topic: &str, payload: &[u8], qos: u8, retain: bool) -> Result<()>;
    fn is_connected(&self) -> bool;
    fn pull_data(&mut self, timeout: u32) -> Result<()>;
}

pub struct SimpleMqttHandler {}

impl MqttHandler for SimpleMqttHandler {
    fn handle(&self, topic: &str, _msg: &MqttMessage) {
        infoln!("got topic {}", topic);
    }
}

#[cfg(feature = "paho")]
pub fn create_mqtt() -> Box<dyn MqttClient> {
    PahoMqttClient::new()
}
